<?php
/**
 * @brief Worldpay
 * @class Worldpay
 * @package App
 * @subpackage  Driver.Payment
 * @author cjli
 */
class Worldpay extends Payment implements Payment_Interface, Payment_Server_Interface
{   
    var $debug;
    var $_paymentInfo;    
    var $MerchantNo;
    var $merchantCode;
    var $merchantPassword;
    var $installationId;
    var $xmlUrl;
    var $xml;

    public function __construct()
    {
        $this->_paymentInfo     = PaymentModel::get_payment_info('Worldpay');
        $this->MerchantNo       = $this->_paymentInfo['config']['MerchantNo'];
        $this->merchantCode     = $this->_paymentInfo['config']['merchantCode'];
        $this->merchantPassword = $this->_paymentInfo['config']['merchantPassword'];
        $this->installationId   = $this->_paymentInfo['config']['installationId'];   
        $debug                  = $this->_paymentInfo['config']['debug'];

        $this->debug = $debug == 1 ? true : false;
        $this->WorldpayXmlUrl($this->debug);
    }

    public function getSettingFields()
    {
        return array(
            'MerchantNo'   => '商户号',
            'merchantCode' => 'XML API账号',
            'merchantPassword' => 'XML 密码',
            'installationId'   => 'installationId',
            'USMerchantNo'   => 'US商户号',
            'USmerchantCode' => 'US XML API账号',
            'USmerchantPassword' => 'US XML 密码',
            'USinstallationId'   => 'US installationId',        
            'currency' => array(
                'name' => '支付币种',
                'type' => 'select',
                'options' => array(
                    'USD' => 'USD',
                    'EUR' => 'EUR',
                    'GBP' => 'GBP',
                    'AUD' => 'AUD',
                    'CAD' => 'CAD',
                ),
                'default' => 'USD',
            ),
            'debug' => array(
                'name' => '当前模式',
                'type' => 'select',
                'options' => array(
                    '1' => 'debug',
                    '2' => '生产环境',
                ),
                'default' => '1',
            ),
        );
    }

    function WorldpayXmlUrl($debug) {
        if($debug)
            $this->xmlUrl = "https://" . $this->merchantCode . ":" . $this->merchantPassword . "@secure-test.worldpay.com/jsp/merchant/xml/paymentService.jsp";
        else
            $this->xmlUrl = "https://" . $this->merchantCode . ":" . $this->merchantPassword . "@secure.worldpay.com/jsp/merchant/xml/paymentService.jsp";
    }

    public function getSubmitForm($orderInfo)
    {   
        //美加两国用指定账号
        if(in_array($orderInfo['delivery_cid'], array(223))){//,38 加拿大暂时不做处理
            $this->MerchantNo       = $this->_paymentInfo['config']['USMerchantNo'];
            $this->merchantCode     = $this->_paymentInfo['config']['USmerchantCode'];
            $this->merchantPassword = $this->_paymentInfo['config']['USmerchantPassword'];
            $this->installationId   = $this->_paymentInfo['config']['USinstallationId']; 
            $this->WorldpayXmlUrl($this->debug);        
        }
        $orderInfo['order_sn_worldpay'] = $orderInfo['order_sn'].'-'.rand(1, 999);
        $orderInfo['country'] = D('region')->where(array('id'=>$orderInfo['delivery_cid']))->getField('iso2_code');
        //生成XML
        $this->getSubmitXML($orderInfo);
        //提交XML到Worldpay
        $result = $this->CreateConnection(); 
        //解析得到的XML数据
        $xmlResult = $this->ParseXML($result);
        if($xmlResult['referenceID'] && $xmlResult['url_togoto']){
            $url_togoto = $xmlResult['url_togoto'];
            return $this->getTogotoForm($orderInfo, $url_togoto);
        }else{
            Log::write('worldpay xml log: '.$result.' >>ParseXML->'.json_encode($xmlResult).' >>order-> '.json_encode($orderInfo['order_sn_worldpay']));
            //Log::write('worldpay xml parse: '.json_encode($xmlResult).' ->by '.json_encode($orderInfo));
            return '';
        }
    }


    public function getTogotoForm($orderInfo, $url_togoto)
    {
        /*  
        https://secure.worldpay.com/jsp/shopper/SelectPaymentMethod.jsp?orderKey=MYMERCHANT^T0211010
        &country=GB&language=en
        &bodyAttr=bgcolor%3D%22black%22
        &fontAttr=face%3D%22arial%22+color%3D%22white%22
        &successURL=http%3A%2F%2Fwww.webshops.int.com%2Fsuccess.asp
        &failureURL=http%3A%2F%2Fwww.webshops.int%2Ffailure.php
        &pendingURL=http%3A%2F%2Fwww.webshops.int%2Fpending.html
        &preferredPaymentMethod=VISA-SSL 
        */
        
        $submiturl = $url_togoto;
        $submit_field = array(
          'country' => $orderInfo['country'],
          'language' => $orderInfo['en'],
          'successURL' => url('payment/callback',array('pay' => 'Worldpay')),
          'failureURL' => url('payment/callback',array('pay' => 'Worldpay')),
          );
        foreach ($submit_field as $key => $val) {
          $submiturl .= '&'.$key.'='.urlencode($val);
        }
        $html = array(
          '<form id="frm" action="' . $submiturl . '" method="post">',
          '<input type="submit" class="pay_button" value="' . L('_PAY_NOW_') . '">',
          '</form>',
        );
        return implode(PHP_EOL, $html);
    }

    public function getSubmitXML($orderInfo)
    {
        //$xml is the order string to send to bibit
        $xml="<?xml version='1.0' encoding='UTF-8'?>
        <!DOCTYPE paymentService PUBLIC '-//WorldPay/DTD WorldPay PaymentService v1//EN' 'http://dtd.worldpay.com/paymentService_v1.dtd'>
        <paymentService version='1.4' merchantCode='".$this->MerchantNo."'>
        <submit>
        <order orderCode = '".$orderInfo['order_sn_worldpay']."' installationId='".$this->installationId."'>
        <description>Men's Custom Suits And Shirts | OWNONLY</description>
        <amount value='".($orderInfo['pay_amount']*100)."' currencyCode = '".$orderInfo['currency']."' exponent = '2'/>
        <orderContent>
        <![CDATA[]]>
        </orderContent>
        <paymentMethodMask>
        <include code='ECMC-SSL'/>
        <include code='VISA-SSL'/>
        <include code='AMEX-SSL'/>
        </paymentMethodMask>
        <shopper>
        <shopperEmailAddress>".$orderInfo['delivery_email']."</shopperEmailAddress>
        </shopper>
        <shippingAddress>
        <address>
        <firstName>".$orderInfo['delivery_first_name']."</firstName>
        <lastName>".$orderInfo['delivery_last_name']."</lastName>
        <street>".$orderInfo['delivery_address'].$orderInfo['delivery_address2']."</street>
        <postalCode>".$orderInfo['delivery_postcode']."</postalCode>
        <city>".$orderInfo['delivery_city']."</city>
        <countryCode>".$orderInfo['country']."</countryCode>
        <telephoneNumber>".$orderInfo['delivery_phone']."</telephoneNumber>
        </address>
        </shippingAddress>
        </order>
        </submit>
        </paymentService>";
        //$xml is the order string to send to bibit
        $this->xml = $xml;      
    }

    function CreateConnection() {
        $ch = curl_init ($this->xmlUrl);
        curl_setopt($ch, CURLOPT_POST,1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $this->xml); //$xml is the xml string
        curl_setopt($ch, CURLOPT_TIMEOUT,20); 
        curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
        //SSL
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        // echo "ch: $ch<HR>" ;

        $result = curl_exec ($ch); // result will contain XML reply from Bibit
        curl_close ($ch);
        if ( $result == false )
            print "Curl could not retrieve page '$this->xmlUrl', curl_exec returns false";

        return $result;
    }
    
    function ParseXML($result) {

        function startElement($parser, $name, $attrs) 
        {
            global $currentTag,$ordercode,$referenceID,$errorcode,$url_togoto;
            $currentTag = $name;

            switch ($name) {
                case "ERROR": 
                /*  
                THERE IS AN XML ERROR REPLY
                1 : internal error, could be everything
                2 : parse error, invalid xml
                3 : invalid number of transactions in batch
                4 : security error
                5 : invalid request
                6 : invalid content, occurs when xml is valid but content of xml not
                7 : payment details in the order element are incorrect
                */
                $errorcode = $attrs['CODE']; //example of how to catch the error code number (i.e. 1 to 7)
                $url_error="error_order.php";
                  break;

                case "REFERENCE":
                  $referenceID = $attrs['ID'];//for storage in your own database
                  break;
                  
                case "ORDERSTATUS":
                  $ordercode = $attrs['ORDERCODE'];
                  break;
                  
                default:
                  break;
            }
        }

        //////////////////
        function endElement($parser, $name) {
            global $currentTag;
            $currentTag = "";
        }

        /////////////////
        function characterData($parser, $result) {

          global $currentTag;
          global $url_togoto;

          switch ($currentTag) {
              case "REFERENCE":
                //there is a REFERENCE so there must be an url which was provided by WorldPay for the actual payment. echo $result;
                $url_togoto=$result;
                break;

              default:
                break;
          }
        }

        global $currentTag,$ordercode,$referenceID,$errorcode,$url_togoto;//define globals
        $xml_parser = xml_parser_create();

        // set callback functions
        xml_set_element_handler($xml_parser, "startElement", "endElement");
        xml_set_character_data_handler($xml_parser, "characterData");

        if (!xml_parse($xml_parser, $result))
        {
            die(sprintf("XML error: %s at line %d",
            xml_error_string(xml_get_error_code($xml_parser)),
            xml_get_current_line_number($xml_parser)));
        }

        // clean up
        xml_parser_free($xml_parser);
        //now we have a few important variables. Depending on what variables are set you can now perform an action like storing id's in your database or refer to a different url.
        $xmlResult  = array(
            'ordercode' => $ordercode,
            'referenceID' => $referenceID,
            'errorcode' => $errorcode,
            'url_togoto' => $url_togoto,
          );
        return $xmlResult;
    }    

    private function checkPost()
    {

    }
    /*
    https://www.webshops.int/success.asp?orderKey=MYADMINCODE^MYMERCHANT^T0211010
    &paymentStatus=AUTHORISED
    &paymentAmount=2600
    &paymentCurrency=EUR
    &mac=0083c47880f0533d773c350ee0d51cfc
    */
    public function callback()
    {
        $post = $_POST ? $_POST : $_GET;
        $orderKey = explode('^', $post['orderKey']);
        $OrderCode = explode('-', $orderKey[2]);
        if ($_POST) {
            $result = array(
              'verified' => false,
              'paidAmount' => ($post['paymentAmount']/100),
              'paymentId' => $orderKey[2],
              'orderNumber' => $OrderCode[0],
              'updateOrderStatus' => false,
              'message' => '',
              'currency' => $post["paymentCurrency"],
            );
            $payment_status = $post['paymentStatus'];
        } else {
            $result = array(
              'verified' => false,
              'paidAmount' => ($post['paymentAmount']/100),
              'paymentId' => $orderKey[2],
              'orderNumber' => $OrderCode[0],
              'updateOrderStatus' => false,
              'message' => '',
              'currency' => $post["paymentCurrency"],
            );
            $payment_status = $post['paymentStatus'];
        }

        /* 验证 */
        if ($payment_status == 'AUTHORISED' || $payment_status == 'CAPTURED') {
            $result['verified'] = true;
            $result['updateOrderStatus'] = true;
            $result['message'] = L('_PAYMENT_SUCCESS_');
        } else {
            $result['message'] = L('_PAYMENT_FAILURE_');
			$result['returnMsg'] = $post['paymentStatus'];
        }
        //var_dump($result);
        //exit;
        return $result;
    }

    public function serverCallback()
    {
        //var_dump($_POST);
        // exit;
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
          $OrderCode = explode('-', $_POST['OrderCode']);
          $result = array(
            'verified' => true,
            'paidAmount' => $_POST['PaymentAmount']/100,
            'paymentId' => $_POST['PaymentId'].' '.$_POST['OrderCode'],
            'orderNumber' => $OrderCode[0],
            'updateOrderStatus' => true,
            'message' => '',
            'currency' => $_POST["PaymentCurrency"],
          );
          $payment_status = $_POST['PaymentStatus'];
          /* 验证 */
          if ($payment_status == 'AUTHORISED' || $payment_status == 'CAPTURED') {
              $result['verified'] = true;
          } else {
              $result['verified'] = false;
          }  
          Log::write('worldpay notice log: '.json_encode($_POST).'checkpost pass');
        } else {
          $result = array(
            'verified' => false,
          );
          Log::write('worldpay notice log: REQUEST_METHOD'.$_SERVER['REQUEST_METHOD'].' '.json_encode($_REQUEST));
        }
        return $result;
    }
}
